package com.sunnyweather.android.logic

import androidx.lifecycle.liveData
import com.sunnyweather.android.logic.dao.PlaceDao
import com.sunnyweather.android.logic.model.Content
import com.sunnyweather.android.logic.model.Weather
import com.sunnyweather.android.logic.network.SunnyWeatherNetwork
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlin.coroutines.CoroutineContext
//仓库层像一个数据获取与缓存的中间层，在本地没有缓存数据的情况下就去网络层获取，如果本地已经有了缓存，就直接将缓存数据返回
object Repository {
    //搜索城市信息的仓库
    fun searchPlaces(query: String) = fire(Dispatchers.IO) {
        val placeResponse = SunnyWeatherNetwork.searchPlaces(query)//调用网络层的SunnyWeatherNetwork.searchPlaces()方法搜索城市数据
        if (placeResponse.code == "200") {//如果获取到数据
            val places = placeResponse.location
            Result.success(places)//包装获取的城市数据列表

        } else {
            Result.failure(RuntimeException("response status is ${placeResponse.code}"))
        }
    }

    //实时天气预报和未来七天天气预报的仓库
    fun refreshWeather(locationId: String) = fire(Dispatchers.IO) {
        coroutineScope {
            val deferredRealtime = async {
                SunnyWeatherNetwork.getRealtimeWeather(locationId)
            }
            val deferredDaily = async {
                SunnyWeatherNetwork.getDailyWeather(locationId)
            }
            val realtimeResponse = deferredRealtime.await()
            val dailyResponse = deferredDaily.await()
            if (realtimeResponse.code == "200" && dailyResponse.code == "200") {
                val weather = Weather(realtimeResponse.now, dailyResponse.daily)
                Result.success(weather)
            } else {
                Result.failure(
                    RuntimeException(
                        "realtime response status is ${realtimeResponse.code}" +
                                "daily response status is ${dailyResponse.code}"
                    )
                )
            }
        }
    }
    //保存数据
    fun savePlace(place: Content) = PlaceDao.savePlace(place)
    //获取被保存的数据
    fun getSavedPlace() = PlaceDao.getSavedPlace()
    //判断是否有数据已被保存
    fun isPlaceSaved() = PlaceDao.isPlaceSaved()

    //为了能将一步获取的数据以响应式编程的方式通知给上一层，通常会返回一个LiveData对象
    private fun <T> fire(context: CoroutineContext, block: suspend () -> Result<T>) =
        liveData<Result<T>>(context) {
            val result = try {
                block()
            } catch (e: Exception) {
                Result.failure<T>(e)
            }
            emit(result)//将包装的数据发射出去，即类似于LiveData的setValue()方法来通知数据变化
        }

}